package cn.zyjblogs.nio.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {
    public static void main(String[] args) {
        //创建ServerSocketChannel -> ServerSocket
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
             //得到一个Selector
             Selector selector = Selector.open()) {
            //绑定一个端口6666，在服务端监听
            final int port = 6666;
            System.out.println("启动监听,监听端口: "+port);
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
            //设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            //把serverSocketChannel 注册到selector  关心 事件为OP_ACCEPT
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            //1
            System.out.println("注册后的selectionKey 数量 = "+selector.keys().size());
            //循环等待客户端链接
            System.out.println("等待客户端链接");
            while (true){
                //等待1秒，如果没有事件发生，就继续
                if (selector.select(1000) == 0){
                    System.out.println("服务器等待了1秒，无连接");
                    continue;
                }
                //如果返回的>0,获取到相关的selectionKey集合
                //1.如果返回的大于0， 表示已经获取到关注的事件的集合
                //2. selector.selectedKeys()返回关注事件的集合
                // 通过selectionKeys反向获取通道
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                //selectionKeys.size() 和 selector.keys().size() 不一样
                //selectionKeys 代表有事件发生的数量
                System.out.println("selectionKeys 数量 = "+selectionKeys.size());
                //遍历Set<SelectionKey>，使用迭代器便利
                Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
                while (keyIterator.hasNext()){
                    //获取到selectionKey
                    SelectionKey key = keyIterator.next();
                    //根据key 对应的通道发生的事件做相应处理
                    //如果是OP_ACCEPT,有客户端链接
                    if (key.isAcceptable()){
                        //给该客户端生成一个SocketChannel
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        //设置为非阻塞
                        socketChannel.configureBlocking(false);
                        System.out.println("客户端连接成功 生成了一个SocketChannel"+socketChannel.hashCode());
                        //将当前socketChannel 注册到selector,关注事件为OP_READ 同时给socketChannel关联一个buffer
                        socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                        System.out.println("客户端连接后, 注册后的selectionKey 数量 = "+selector.keys().size());
                    }
                    //发生OP_READ事件
                    if (key.isReadable()){
                        //通过key反向获取到对应的channel
                        SocketChannel channel = (SocketChannel)key.channel();
                        //获取到该channel关联buffer
                        ByteBuffer buffer = (ByteBuffer)key.attachment();
                        //将buffer读取到channel中
                        channel.read(buffer);
                        System.out.println("form 客户端 "+new String(buffer.array()).trim());
                    }
                    //手动从集合中移动当前的selectionKey，防止重复操作
                    keyIterator.remove();
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
